#include "ClientTransfer.h"

//参数jpgPath:保存jpg序列的目录
CClientTransfer::CClientTransfer(const char *jpgPath, const char *ip, const char *port)
{

    std::string strJpgPath(jpgPath);
    m_jpgPath = strJpgPath;

    //	分配内存
    image_buff desc;
    desc.pBuff = nullptr;
    desc.MAXlength = MAX_BUFF_SIZE;
    desc.width = 0;
    desc.high = 0;

    for (int i = 0; i < 100; ++i)
    {
        desc.pBuff = new uint8_t[MAX_BUFF_SIZE];
        IdleList.push_back(desc);
    }

    std::cout << "[m_jpgPath]:" << m_jpgPath << std::endl;

    m_PicId = 0;
    m_coutSend=0;
    m_readQuit=false;
    m_sendQuit = false;

    //ip::tcp::endpoint ep(ip::address_v4::from_string("192.168.1.60"), 8112);
    ip::tcp::endpoint ep(ip::address_v4::from_string(ip), atoi(port));
    std::cout << __LINE__ << __FILE__ << std::endl;
    m_sock = new CClientSock(ep);
    std::cout << __LINE__ << __FILE__ << std::endl;
}

//
CClientTransfer::~CClientTransfer(void)
{
    //
    std::list<image_buff>::iterator iter;

    //注意加锁
    LOCK lock(iomutex);
    for (iter = SendBuffList.begin(); iter != SendBuffList.end(); ++iter)
    {
        delete[]((*iter).pBuff);
        (*iter).pBuff = NULL;
    }

    SendBuffList.clear();

    for (iter = IdleList.begin(); iter != IdleList.end(); ++iter)
    {
        delete[]((*iter).pBuff);
        (*iter).pBuff = NULL;
    }
    cout << __LINE__ << __FILE__ << endl;
    IdleList.clear();

    if (m_sock)
    {
        delete m_sock;
        m_sock = NULL;
    }
}

//函数功能:从jpgPath中获取jpeg数据
bool CClientTransfer::GetJpegData(image_buff &imageBuff, std::string jpgPath)
{
    //
    bool status = false;

    unsigned int nJpgLen = 0;
    cv::Mat src;
    src = cv::imread(jpgPath.c_str());
    if (src.data == NULL)
    {
        std::cout << "Error imread Error! return NULL data!" << std::endl;
        abort();
    }

    int len = src.cols * src.rows * 3;

    if (len > imageBuff.MAXlength)
    {

        return false;
        std::cout << "Error! The iamge is too large ,overload!" << std::endl;
    }
    imageBuff.high = src.rows;
    imageBuff.width = src.cols;
    int Channels = src.channels();
    imageBuff.channels = Channels;

    uint8_t *p1 = (uint8_t *)malloc(sizeof(uint8_t) * len);
    p1 = imageBuff.pBuff;
    char writeP1Buffer[100];
    for (int i = 0; i < len; i++) //Mat to Ptr
    {
        p1[i] = (uint8_t)src.at<cv::Vec3b>(i / (src.cols * 3), (i % (src.cols * 3)) / 3)[i % 3];
    }

    return true;
}

//函数功能:从文件夹下枚举.jpg图片,放入到jpg的vector容器中
bool CClientTransfer::scanFilesUseRecursive(const string &rootPath, vector<string> &container)
{
    //

    namespace fs = boost::filesystem;
    fs::path fullpath(rootPath);

    vector<string> &ret = container;

    //判断路径是否存在
    if (!fs::exists(fullpath))
    {
        return false;
    }

    fs::recursive_directory_iterator end_iter;
    std::cout << __LINE__ << "CClientTransfer::scanFilesUseRecursive" << std::endl;
    for (fs::recursive_directory_iterator iter(fullpath); iter != end_iter; iter++)
    {

        try
        {
            //是文件名&&.jpg
            if (!fs::is_directory(*iter) && (fs::extension(*iter) == ".jpg" || fs::extension(*iter) == ".JPG" || fs::extension(*iter) == ".jpeg" || fs::extension(*iter) == ".JPEG"))
            {
                //
                std::string jpgstring = iter->path().string();

                ret.push_back(jpgstring);
                std::cout << *iter << " is a file" << std::endl;
            }
        }
        catch (const std::exception &ex)
        {
            std::cerr << ex.what() << std::endl;
            continue;
        }
    }

    return true;
}

void TransferThread(image_buff &imageBuff)
{
}

void CClientTransfer::ReadJpegThread(void *arg)
{
    //
    CClientTransfer *pThis = (CClientTransfer *)arg;

    while (1)
    {
        std::cout << __LINE__ << " " << __FILE__ << std::endl;
        if (pThis->m_readQuit)
        {
            break;
        }

        pThis->ReadJpegData();
    }
}

//读jpeg数据
void CClientTransfer::ReadJpegData(void)
{
    image_buff struImageBuff;
    memset(&struImageBuff, 0, sizeof(struImageBuff));

    //多线程必须加锁
    if (IdleList.size() > 0)
    {
        LOCK lock(iomutex);               //锁定mutex
        struImageBuff = IdleList.front(); // assign memeory
        IdleList.pop_front();
    }
    else
    {
        //使用boost ::时间库替换
        boost::this_thread::sleep(boost::posix_time::milliseconds(5));
        return;
    }

    LOCK lock(iomutex); //锁定mutex
    if (m_PicId < m_vecFilePic.size())
    {
        //
        std::string jpgPath = m_vecFilePic[m_PicId].c_str();
        cout << "jpgPath:" << jpgPath << endl;

        if (GetJpegData(struImageBuff, jpgPath))
        {
            m_PicId++;

            SendBuffList.push_back(struImageBuff);
            cout << "read a jpeg image" << endl;
        }
        else
        {
            IdleList.push_back(struImageBuff);
        }
    }
    else
    {

    
        IdleList.push_back(struImageBuff);
        std::string strTime = boost::posix_time::to_iso_string(

            boost::posix_time::second_clock::local_time());

        int pos = strTime.find('T');

        strTime.replace(pos, 1, std::string("-"));

        strTime.replace(pos + 3, 0, std::string(":"));

        strTime.replace(pos + 6, 0, std::string(":"));
        cout << "!all jpeg image read complete at " << strTime << endl;

         m_readQuit=true;
    }
}

//发送Jpeg数据
void CClientTransfer::SendJpegThread(void *arg)
{
    //
    CClientTransfer *pThis = (CClientTransfer *)arg;

    while (1)
    {
        if (pThis->m_sendQuit)
        {
            //
            break;
        }

        pThis->SendJpegData();
    }
}

void CClientTransfer::SendJpegData(void)
{
    cout << __LINE__ << __FILE__ << endl;
    ImageInfo ProtoImageBuff;
    image_buff struImageBuff;
    memset(&struImageBuff, 0, sizeof(struImageBuff));
    cout << "SendBuffList.size():" << SendBuffList.size() << endl;
    //加锁

    if (SendBuffList.size() > 0)
    {
        LOCK lock(iomutex); //锁定mutex
        struImageBuff = SendBuffList.front();
        SendBuffList.pop_front();
    }
    else
    {

        cout << __LINE__ << __FILE__ << endl;

        boost::this_thread::sleep(boost::posix_time::milliseconds(5));
        return;
    }
    uint32_t lenImage = struImageBuff.high * struImageBuff.width * struImageBuff.channels;

    void *rtBuff = new uint32_t[sizeof(uint32_t) * (lenImage + 3)];
    memset(rtBuff, 0x00, (sizeof(uint32_t) * (lenImage + 3)));
    ProtoImageBuff.set_high(struImageBuff.high);
    ProtoImageBuff.set_width(struImageBuff.width);
    ProtoImageBuff.set_channel(struImageBuff.channels);
    cout << "struImageBuff.width:" << struImageBuff.width << endl;

    uint32_t headPackage = (lenImage + 3) * sizeof(uint32_t); // data: size of Protobuf Image serizeied
    uint32_t *fullPackage = new uint32_t[(1 + 1 + 1 + 1 + lenImage) * sizeof(uint32_t)];
    fullPackage[0] = headPackage;

    cout << "struImageBuff.high=" << struImageBuff.high << endl;

    //   string strDataImage ( (const char * )struImageBuff.pBuff );
    //  string strDataImage=static_cast<string>((const char * )struImageBuff.pBuff);

    // //size_t lenStrBuff=strlen((char *)struImageBuff.pBuff);
    if (struImageBuff.pBuff == nullptr)
    {
        cout << "Error!: struImageBuff.pBuff is nullptr" << endl;
        return;
    }

    //     string strDataImage;
    //    for(int i=0;i<struImageBuff.high*struImageBuff.width*struImageBuff.channels;i++)
    // {
    //    //printf("[%d]:%x\t ",i,struImageBuff.pBuff[i]);

    //          strDataImage.append((char)struImageBuff.pBuff[i]);

    //  }

    string strDataImage(reinterpret_cast<char *>(struImageBuff.pBuff), struImageBuff.high * struImageBuff.width * struImageBuff.channels);
    if (strDataImage.length() == 0)
    {
        cout << "Error!strDataImage.length()=-0" << endl;
        return;
    }

    ProtoImageBuff.set_dataimage(strDataImage);
    cout << "strDataImage.length()=" << strDataImage.length() << endl;

    ProtoImageBuff.SerializeToArray(rtBuff, (sizeof(uint32_t) * (lenImage + 3)));

    memcpy(fullPackage + 1, rtBuff, sizeof(uint32_t) * (lenImage + 3));

#if 1 // debug: wreite data for before send... for check
    cout << "mark:parsefromearray() nned size:" << sizeof(uint32_t) * (lenImage + 3) << endl;
    uint32_t *takePackageBuffer = fullPackage + 1;

    ImageInfo outProtoImageBuff;
    outProtoImageBuff.ParseFromArray(takePackageBuffer, (sizeof(uint32_t) * (lenImage + 3)));

    string outStrImageData = outProtoImageBuff.dataimage();
    int srcHigh = outProtoImageBuff.high();

    int srcWidth = outProtoImageBuff.width();

    int srcChannel = outProtoImageBuff.channel();

    int srcLen = srcHigh * srcWidth * srcChannel;

    const char *tPtrBuff = outStrImageData.c_str();

    uint8_t *PtrBuff = new uint8_t[outStrImageData.size()];

    for (int i = 0; i < outStrImageData.length(); i++)

    {

        PtrBuff[i] = tPtrBuff[i];
    }

    cv::Mat tImgOrig(srcHigh, srcWidth, CV_8UC3, cv::Scalar(0, 0, 0));

    ucharToMat(PtrBuff, tImgOrig, 0); //

    std::string strTime = boost::posix_time::to_iso_string(

        boost::posix_time::second_clock::local_time());

    int pos = strTime.find('T');

    strTime.replace(pos, 1, std::string("-"));

    strTime.replace(pos + 3, 0, std::string(":"));

    strTime.replace(pos + 6, 0, std::string(":"));

    char m_cBuf[10 * 500];
static int markConfilic=0;
    sprintf(m_cBuf, "./PreSend_%s_%d.jpg", strTime.c_str(), markConfilic);
     markConfilic++;

    std::cout << "m_cBuf" << m_cBuf << std::endl;

    cv::imwrite(m_cBuf, tImgOrig);

#endif //--1

    //调用boost Asio发送数据
    size_t retSend = m_sock->send(fullPackage, fullPackage[0]);
    cout << "retSend=" << retSend << endl;
    IdleList.push_back(struImageBuff);

    //size_t rettSend = boost::asio::write(m_sock-, boost::asio::buffer(fullPackage,fullPackage[0] ));

    LOCK lock(iomutex); //锁定mutex
                        //IdleList.push_back(struImageBuff);

    std::string strTime1 = boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time());

    int pos1 = strTime1.find('T');

    strTime1.replace(pos1, 1, std::string("-"));

    strTime1.replace(pos1 + 3, 0, std::string(":"));

    strTime1.replace(pos1 + 6, 0, std::string(":"));
    cout << "send a jpeg image, at" << strTime1 << endl;

    char *retOK = new char[2];
    m_sock->recv(retOK, 2);

    while (strcmp(retOK, "ok") != 0)
    {
        cout << "Waing server recive current data ..." << endl;
    }

m_coutSend++;

if(m_coutSend==m_vecFilePic.size())
{
    cout<<"send all jpg?,m_coutSend="<< m_coutSend <<" m_vecFilePic.size()="<<m_vecFilePic.size()<<endl;
m_sendQuit=true;
}
    printf("%s\n", retOK);
    // boost::this_thread::sleep(boost::posix_time::milliseconds(6000)); //take_debug wait server to redeived data....^^
}

void CClientTransfer::StartThread(void)
{

    scanFilesUseRecursive(m_jpgPath, m_vecFilePic);

    cout << "m_vecFilePic.size:" << m_vecFilePic.size() << endl;
    m_ReadThread = boost::thread(boost::bind(&CClientTransfer::ReadJpegThread, this));
    m_SendThread = boost::thread(boost::bind(&CClientTransfer::SendJpegThread, this));
}

//
void CClientTransfer::WaitThreadTerminate(void)
{
    //
    m_ReadThread.join();
    m_SendThread.join();
}

int CClientTransfer::ucharToMat(const uint8_t *p2, cv::Mat &src, int flag)

{

    int img_width = src.cols;

    int img_height = src.rows;

    //Mat img(Size(img_width, img_height), CV_8UC3);

    for (int i = 0; i < img_width * img_height * 3; i++)

    {

        src.at<cv::Vec3b>(i / (img_width * 3), (i % (img_width * 3)) / 3)[i % 3] = p2[i]; //BGR閺嶇厧绱�

        // src.at<cv::Vec3b>(i / (img_width * 3), (i % (img_width * 3)) / 3)[i % 3] = p2[i];//閿燂拷??娑撶療GB娴ｈ法鏁�
    }

    flag = 1;

    return flag;
}
